package com.ict.web.service.impl;

import java.time.Instant;
import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ict.common.core.domain.entity.SysUser;
import com.ict.common.core.text.Convert;
import com.ict.common.utils.DateUtils;
import com.ict.common.utils.SecurityUtils;
import com.ict.common.utils.StringUtils;
import com.ict.common.utils.uuid.IdUtils;
import com.ict.system.service.ISysUserService;
import com.ict.web.constant.Constants;
import com.ict.web.constant.ProjectStatusEnum;
import com.ict.web.domain.Approval;
import com.ict.web.domain.ExpertInformationSheet;
import com.ict.web.domain.ExtractExpert;
import com.ict.web.domain.ReviewTask;
import com.ict.web.dto.ExpertValuateDto;
import com.ict.web.dto.ExtractExpertEditDto;
import com.ict.web.mapper.ExtractExpertMapper;
import com.ict.web.service.*;
import com.ict.web.vo.ExpertValuateVo;
import com.ict.web.vo.ExtractExpertDetailVo;
import com.ict.web.vo.ProjectManagementDetailsVo;
import com.ict.web.vo.ReviewTaskDetailVo;
import io.jsonwebtoken.lang.Collections;
import org.apache.catalina.security.SecurityUtil;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

import javax.annotation.Resource;


/**
 * 抽取专家Service业务层处理
 * 
 * @author xc
 * @date 2022-02-25
 */
@Service
public class ExtractExpertServiceImpl extends ServiceImpl<ExtractExpertMapper, ExtractExpert> implements IExtractExpertService
{
    @Autowired
    private ExtractExpertMapper extractExpertMapper;
    @Autowired
    private IExpertInformationSheetService expertInformationSheetService;
    @Resource
    private IApprovalService approvalService;
    @Autowired
    private IProjectManagementService projectManagementService;
    @Autowired
    private IReviewTaskService reviewTaskService;
    @Override
    public boolean batchUpdate(List<ExtractExpertEditDto> list,Long  reviewTaskId) {
        List<ExtractExpert> extractExpertList = new ArrayList<>();
        list.forEach(s->{
            ExtractExpert extractExpert = extractExpertMapper.selectById(s.getExtractExpertId());
            Assert.isTrue(StringUtils.isNotNull(extractExpert),"未找到该抽取专家表的信息");
            BeanUtils.copyProperties(s,extractExpert);
            extractExpert.setUpdateTime(LocalDateTime.now());
            extractExpertList.add(extractExpert);
            extractExpertMapper.updateById(extractExpert);
        });
        //评审任务
        ReviewTask reviewTask = reviewTaskService.getById(reviewTaskId);
        Assert.isTrue(StringUtils.isNotNull(reviewTask),"未找到改评审任务");
        reviewTask.setExpertStatus(ReviewTask.EXTRACT_STATUS_EVALUATED);
        reviewTask.setUpdateTime(LocalDateTime.now());
        return reviewTaskService.updateById(reviewTask);
    }

    @Override
    public int batchInsertExtractExpert(List<ExtractExpert> list) {
        return extractExpertMapper.batchInsert(list);
    }

    @Override
    public int deleteReviewTask(Long reviewTaskId) {
        Long userId = SecurityUtils.getUserId();
        QueryWrapper<ExpertInformationSheet> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("user_id",userId);
        ExpertInformationSheet informationSheet = expertInformationSheetService.getOne(queryWrapper);
        Assert.isTrue(StringUtils.isNotNull(informationSheet),"该用户未绑定专家");
        ExtractExpert extractExpert = extractExpertMapper.selectReviewTask(reviewTaskId, informationSheet.getExpertId());
        extractExpert.setDelFlag(ExtractExpert.DELETE_STATUS_DELETED);
        return extractExpertMapper.updateById(extractExpert);
    }

    @Override
    public int update(ExtractExpertDetailVo dto) {
        Assert.isTrue(StringUtils.isNotNull(dto.getExtractExpertId()),"抽取表id不能为空");
        ExtractExpert extractExpert = extractExpertMapper.selectById(dto.getExtractExpertId());
        Assert.isTrue(StringUtils.isNotNull(extractExpert),"抽取表信息不能为空");
        BeanUtils.copyProperties(dto,extractExpert);
        return extractExpertMapper.updateById(extractExpert);
    }
    @Override
    public int batchUpdateExtractExpert(List<ExtractExpert> list) {
        return extractExpertMapper.batchUpdate(list);
    }

    @Override
    public int approval(Long extractExpertId, String status,Long reviewTaskId) {
        //若大数据局同意申请取消后状态变更为“同意取消”，若不同意状态变更为“已接受”。
        ExtractExpert extractExpert = extractExpertMapper.selectById(extractExpertId);
        Assert.isTrue(StringUtils.isNotNull(extractExpert),"未找到该抽取表信息");
        ReviewTask reviewTask = reviewTaskService.getById(reviewTaskId);
        Assert.isTrue(StringUtils.isNotNull(reviewTask),"未找到该评审任务");
        //方案评审
        if(ReviewTask.REVIEW_TYPE_PROGRAMME.equals(reviewTask.getReviewType())){
            //更新该专家审核进程
            ProjectManagementDetailsVo projectManagement = projectManagementService.selectProjectManagementListByReviewIds(reviewTaskId);
            Assert.isTrue(StringUtils.isNotNull(projectManagement),"未找到该评审任务对应的项目信息");
            Approval approval = approvalService.getApproval(projectManagement.getProId(), ProjectStatusEnum.APPROVAL_CANCEL_APPROVAL_AGAIN.get().getStatus(), extractExpert.getExpertId(), null);
            Assert.isTrue(StringUtils.isNotNull(approval),"未找到该专家申请取消的审核记录");
            approval.setApprovalOperator(SecurityUtils.getNickName());
            approval.setEndTime(LocalDateTime.now());
            //更新评审任务、抽取表状态、申请取消审核结果
            if(ExtractExpert.APPROVAL_CANCEL.equals(status)){
                extractExpert.setStatus(ExtractExpert.STATUS_APPLY_APPROVAL_AGREE_CANCEL);
                extractExpert.setReceiveStatus(ExtractExpert.RECEIVE_STATUS_AGREE_CANCEL);
                approval.setApprovalStatus(ProjectStatusEnum.APPROVAL_CANCEL_APPROVED_AGAIN_YES.get().getStatus());
                approval.setApprovalResult("同意取消");
            }else if(ExtractExpert.APPROVAL_NOT_CANCEL.equals(status)){
                //新增的专家在线预审时间：获取项目在线预审的创建时间
                List<Approval> proApprovalList = approvalService.lambdaQuery().eq(Approval::getProjectId, projectManagement.getProId())
                        .eq(Approval::getApprovalStatus, ProjectStatusEnum.ONLINE_PREQUALIFICATION_PENDING_APPROVAL.get().getStatus())
                        .eq(Approval::getApprovalType, Approval.APPROVAL_TYPE_PROJECT_MANAGE).list();
                proApprovalList.sort(Comparator.comparing(Approval::getCreateTime).reversed());
                LocalDateTime proCreateTime = proApprovalList.get(0).getCreateTime();
                //旧的专家在线预审时间修改（小于申请取消时间的创建时间）
                //获取项目的在线预审记录
                Approval projectApproval = approvalService.getApprovalByCreateTime(projectManagement.getProId(), ProjectStatusEnum.ONLINE_PREQUALIFICATION_PENDING_APPROVAL.get().getStatus(), null,
                        Approval.APPROVAL_TYPE_PROJECT_MANAGE, null);
                //修改申请取消前上一个在线预审记录的创建时间
                Approval olApproval = approvalService.getApprovalByCreateTime(projectManagement.getProId(), null, extractExpert.getExpertId(),
                        Approval.APPROVAL_TYPE_EXPERT, projectApproval.getCreateTime());
                List<Approval> expertApprovalList = approvalService.lambdaQuery().eq(Approval::getProjectId, projectManagement.getProId())
                        .eq(Approval::getExpertId, extractExpert.getExpertId())
                        .eq(Approval::getApprovalType, Approval.APPROVAL_TYPE_EXPERT).list();
                expertApprovalList.sort(Comparator.comparing(Approval::getStartTime).reversed());
                LocalDateTime applyCreateTime = expertApprovalList.get(0).getCreateTime();
                olApproval.setCreateTime(applyCreateTime.minus(1, ChronoUnit.SECONDS));
                approvalService.updateById(olApproval);
                approval.setApprovalResult("不同意取消");
                approval.setApprovalStatus(ProjectStatusEnum.APPROVAL_CANCEL_APPROVED_AGAIN_NO.get().getStatus());
                extractExpert.setReceiveStatus(ExtractExpert.RECEIVE_STATUS_ACCEPT);
                reviewTask.setExpertStatus(ReviewTask.EXTRACT_STATUS_ACCEPTED);
                //不同意取消，该抽取表状态回到回到上一个状态
                extractExpert.setStatus(extractExpert.getApplyCancelStatus());
                String extractNode = extractExpert.getExtractNode();
                //TODO : 在线预审-待审核：不同意当前申请取消（在线预审审核状态为待审核），该专家新增在线预审待审核记录（创建时间为项目在线预审的创建时间）
                //      在线预审-已审核：不同意当前申请取消（在线预审审核状态为已审核）且所有专家都完成在线预审，每个专家更新抽取表状态为已审批
                //                      评审任务状态、项目状态、审核进程更新为意见汇总
                //     现场论证-待开始：不同意当前申请取消（现场论证状态为待开始），新增该专家现场论证待开始审核进程
                //节点为：在线预审节点，状态为待审批
                if(ProjectStatusEnum.ONLINE_PREQUALIFICATION_PENDING_APPROVAL.get().getStatus().equals(extractNode)){
                    approvalService.save(new Approval(IdUtils.snowId(),projectManagement.getProId(),ProjectStatusEnum.ONLINE_PREQUALIFICATION_PENDING_APPROVAL.get().getStage(),
                            ProjectStatusEnum.ONLINE_PREQUALIFICATION_PENDING_APPROVAL.get().getNode(),LocalDateTime.now(),null,null,ProjectStatusEnum.ONLINE_PREQUALIFICATION_PENDING_APPROVAL.get().getStatus(),
                            "/",null, null,null, proCreateTime,Approval.APPROVAL_TYPE_EXPERT,extractExpert.getExpertId(),null));

                //节点为：在线预审节点，状态为已审批
                }else if(ProjectStatusEnum.ONLINE_PREQUALIFICATION_APPROVED.get().getStatus().equals(extractNode)){
                    approvalService.save(new Approval(IdUtils.snowId(),projectManagement.getProId(),ProjectStatusEnum.ONLINE_PREQUALIFICATION_APPROVED.get().getStage(),
                            ProjectStatusEnum.ONLINE_PREQUALIFICATION_APPROVED.get().getNode(),LocalDateTime.now(),LocalDateTime.now(),null,ProjectStatusEnum.ONLINE_PREQUALIFICATION_APPROVED.get().getStatus(),
                            "/",null, null,null, proCreateTime,Approval.APPROVAL_TYPE_EXPERT,extractExpert.getExpertId(),null));
                    //所有专家都完成在线预审
                    ReviewTaskDetailVo reviewTaskDetailVo = reviewTaskService.reviewTaskDetailByProId(projectManagement.getProId());
                    Assert.isTrue(StringUtils.isNotNull(reviewTaskDetailVo),"未找到该项目的评审任务");
                    List<ExtractExpertDetailVo> extractExpertList = reviewTaskDetailVo.getExtractExpertList();
                    List<ExtractExpertDetailVo> collect = extractExpertList.stream().filter(
                            s -> s.getExtractNode().equals(ProjectStatusEnum.ONLINE_PREQUALIFICATION_APPROVED.get().getStatus())).collect(Collectors.toList());
                    if(reviewTaskDetailVo.getExpertNum().equals(String.valueOf(collect.size()))){
                        //项目的审核状态为意见汇总待审批
                        approvalService.save(new Approval(IdUtils.snowId(),projectManagement.getProId(),ProjectStatusEnum.COMMENTS_SUMMARY_TO_BE_APPROVED.get().getStage(),
                                ProjectStatusEnum.COMMENTS_SUMMARY_TO_BE_APPROVED.get().getNode(),LocalDateTime.now(),null,null,ProjectStatusEnum.COMMENTS_SUMMARY_TO_BE_APPROVED.get().getStatus(),
                                "/",null, null,null, LocalDateTime.now(),Approval.APPROVAL_TYPE_PROJECT_MANAGE));
                        projectManagement.setIsState(ProjectStatusEnum.COMMENTS_SUMMARY_TO_BE_APPROVED.get().getStatus());
                        projectManagement.setNode(ProjectStatusEnum.COMMENTS_SUMMARY_TO_BE_APPROVED.get().getNode());
                        projectManagement.setStag(ProjectStatusEnum.COMMENTS_SUMMARY_TO_BE_APPROVED.get().getStage());
                        reviewTask.setNode(ProjectStatusEnum.COMMENTS_SUMMARY_TO_BE_APPROVED.get().getNode());
                        reviewTask.setNodeStatus(ProjectStatusEnum.COMMENTS_SUMMARY_TO_BE_APPROVED.get().getStatus());
                        //抽取表下所有抽取出的状态为待开始
                        List<ExtractExpert> arrayList = new ArrayList<>();
                        List<ExtractExpert> extractExperts = reviewTaskService.getExtractExpertList(reviewTaskId);
                        Assert.isTrue(StringUtils.isNotEmpty(extractExperts),"该评审任务未找到专家抽取表信息");
                        extractExperts.stream().forEach(s->{
                            ExtractExpert expert = new ExtractExpert();
                            BeanUtils.copyProperties(s,expert);
                            expert.setStatus(ExtractExpert.STATUS_NOT_START);
                            expert.setExtractNode(Constants.ON_SITE_DEMONSTRATION_TO_BE_REVIEWED);
                            arrayList.add(expert);
                        });
                        extractExpertMapper.batchUpdate(arrayList);
                    }
                //节点为：现场论证节点，状态为待开始
                }else if(ProjectStatusEnum.ON_SITE_DEMONSTRATION_TO_BE_REVIEWED.get().getStatus().equals(extractNode)){
                    //更新上一个专家现场论证审核进程
                    reviewTask.setExpertStatus(ReviewTask.EXTRACT_STATUS_NOT_EVALUATE);
                    approvalService.save(new Approval(IdUtils.snowId(),projectManagement.getProId(),ProjectStatusEnum.ON_SITE_DEMONSTRATION_TO_BE_REVIEWED.get().getStage(),
                            ProjectStatusEnum.ON_SITE_DEMONSTRATION_TO_BE_REVIEWED.get().getNode(),LocalDateTime.now(),null,null,ProjectStatusEnum.ON_SITE_DEMONSTRATION_TO_BE_REVIEWED.get().getStatus(),
                            "/",null, null,null, LocalDateTime.now(),Approval.APPROVAL_TYPE_EXPERT,extractExpert.getExpertId(),null));
                }else {
                    Assert.isTrue(false,projectManagement.getNode()+"节点，不允许审核申请取消操作");
                }
            }else{
                Assert.isTrue(false,"status传参异常");
            }
            extractExpert.setUpdateTime(LocalDateTime.now());
            approvalService.updateById(approval);
            reviewTaskService.updateById(reviewTask);
        //年度评审
        }else {
            Long planId = reviewTask.getPlanId();
            List<Approval> approvalList = approvalService.lambdaQuery().eq(Approval::getExpertId, extractExpert.getExpertId()).eq(Approval::getPlanId, planId)
                    .eq(Approval::getApprovalType, Approval.APPROVAL_TYPE_EXPERT)
                    .eq(Approval::getApprovalStatus,ProjectStatusEnum.APPROVAL_CANCEL_APPROVAL_AGAIN.get().getStatus()).list();
            Assert.isTrue(StringUtils.isNotEmpty(approvalList),"专家年度审核记录为空");
            Approval approval = approvalList.get(0);
            approval.setApprovalOperator(SecurityUtils.getNickName());
            approval.setEndTime(LocalDateTime.now());
            if(ExtractExpert.APPROVAL_CANCEL.equals(status)){
                extractExpert.setStatus(ExtractExpert.STATUS_APPLY_APPROVAL_AGREE_CANCEL);
                extractExpert.setReceiveStatus(ExtractExpert.RECEIVE_STATUS_AGREE_CANCEL);
                approval.setApprovalStatus(ProjectStatusEnum.APPROVAL_CANCEL_APPROVED_AGAIN_YES.get().getStatus());
                approval.setApprovalResult("同意取消");
            }else if(ExtractExpert.APPROVAL_NOT_CANCEL.equals(status)){
                //不同意取消，该抽取表的状态变为现场论证的待开始,并新增一条现场论证待开始审核记录
                extractExpert.setStatus(ExtractExpert.STATUS_NOT_START);
                extractExpert.setReceiveStatus(ExtractExpert.RECEIVE_STATUS_ACCEPT);
                approval.setApprovalStatus(ProjectStatusEnum.APPROVAL_CANCEL_APPROVED_AGAIN_NO.get().getStatus());
                approval.setApprovalResult("不同意取消");
                //申请取消审核操作，更新评审任务的状态
                ReviewTaskDetailVo reviewTaskDetailVo = reviewTaskService.reviewTaskDetailByTaskId(reviewTaskId);
                List<ExtractExpertDetailVo> extractExpertList = reviewTaskDetailVo.getExtractExpertList();
                Assert.isTrue(StringUtils.isNotEmpty(extractExpertList),"未找到该评审任务对应的抽取表信息");
                List<ExtractExpertDetailVo> collect = extractExpertList.stream().filter(s -> s.getReceiveStatus().equals(ExtractExpert.RECEIVE_STATUS_ACCEPT)).collect(Collectors.toList());
                //全部抽取表状态为已接受时，评审任务状态为已接受
                if(extractExpertList.size()==(collect.size()+1)
                        && ExtractExpert.APPROVAL_NOT_CANCEL.equals(status)){
                    reviewTask.setExpertStatus(ReviewTask.EXTRACT_STATUS_ACCEPTED);
                    //每个抽取专家新增现场论证审核进程
                    List<Approval> approvalPlanList = new ArrayList<>();
                    extractExpertList.stream().forEach(s->{
                        Approval approval1 = new Approval(IdUtils.snowId(), null, ProjectStatusEnum.ON_SITE_DEMONSTRATION_TO_BE_REVIEWED.get().getStage(),
                                ProjectStatusEnum.ON_SITE_DEMONSTRATION_TO_BE_REVIEWED.get().getNode(), LocalDateTime.now(), null, null, ProjectStatusEnum.ON_SITE_DEMONSTRATION_TO_BE_REVIEWED.get().getStatus(),
                                "/", null, null, null, LocalDateTime.now(), Approval.APPROVAL_TYPE_EXPERT, extractExpert.getExpertId(), planId);
                        approvalPlanList.add(approval1);
                    });
                }else {
                    reviewTask.setExpertStatus(ReviewTask.EXTRACT_STATUS_NOT_ACCEPT);
                }
                reviewTask.setUpdateTime(LocalDateTime.now());
                reviewTaskService.updateById(reviewTask);
            }else{
                Assert.isTrue(false,"status传参异常");
            }
            extractExpert.setUpdateTime(LocalDateTime.now());
            approvalService.updateById(approval);
        }

        return extractExpertMapper.updateById(extractExpert);
    }

    @Override
    public List<ExpertValuateVo> getExpertValuate(ExpertValuateDto dto) {
        return extractExpertMapper.getExpertValuate(dto);
    }
}
